Previous Page TOC Next Page


9 — Multimedia

by Bill Hatfield

Multimedia is the buzzword of the '90s. Although there was much talk and some work done in multimedia in the late '80s, real applications that deserved that title have come into their own in just the last few years. Today you see more and more graphics, sound, music, and video being skillfully (and sometimes not so skillfully) woven together into the applications you buy. And this convergence of technologies is producing something beyond what you usually might think of as a PC. It is creating an interactive television/learning station that promises to be the cornerstone of future media.

But what about today? Can multimedia applications be put together easily, without expensive hardware? The answer is yes. With a standard PC today and a sound card, Visual Basic programmers have all they need to create and distribute high-quality multimedia applications.

And you're going to get started in this chapter. Here, I'll introduce you to an integrated and powerful control called the Media Control Interface (MCI), which enables you to play recorded sounds, music, and video from files inside your PC and even standard media players like audio CD players, VCRs, and video disc players. All from one simple control.

Then I'll show you how to go beyond the control and access multimedia capabilities through Win32. Although I can't hope to completely immerse you in the technology of tomorrow in just one chapter, I do hope to at least get your feet wet and point you in the right direction for your own exploration.

Introducing the Media Control Interface

The great thing about Windows is that it enables you to take advantage of all the different devices that a user might have hooked up to his or her computer without having to get elbow deep in the complexities of each. This level of abstraction is made possible through device drivers. Device drivers handle all the little details that you don't want to and provide you with a clean, simple interface to the hardware. Nowhere is this abstraction of complexity made more clear than it is in the Media Control Interface and the MCI control.

When you add the MCI control to your toolbox and then place one on your form, it doesn't immediately inspire awe (see Figure 9.1).


Figure 9.1. The Media Control Interface control on a form.

The MCI control looks like the controls you might see on a tape recorder or a CD player. Most media can be thought of as a tape player of some type. The play, rewind, fast-forward, pause, and stop controls just as easily can apply to an audio CD, an AVI video clip, or a WAV file.

Because you probably are eager to see this control put to work, I'll walk you through creating a simple audio CD player. Of course, this process will work only if you have a CD-ROM drive hooked up to your system. If you don't... Where've you been? Go buy one...

Project 1 A CD Player

"But," you protest, "I already have a nifty audio CD player that came with Windows. It even starts up automatically when I drop an audio CD into my drive! I don't need to create one..."

Hmm. That may be so, but I want you to say two words with me: academic exercise. Good.

Of course, you already have an audio CD player, but suppose that you want to add functionality to it. Or suppose that you want to integrate it with another application you are writing. In these cases, you would have to have access to the guts of the thing. And that's exactly what you'll have when you finish this little project.

To create a CD player, follow these steps:

  1. Start a new project. Add WINMMSYS.TXT (in your winapi folder) to your project. It has some constant definitions you'll use later.

  2. Add the MCI control to your project by choosing Custom Controls from the Tools menu (or pressing Ctrl+T). The Custom Controls dialog appears. Scroll down and click the Microsoft Multimedia Control option and click OK.

  3. Drop an MDI control on the form. Now drop four labels above the control. The first label's Caption should be Track. The second label should be blank, but name it lblTrack. The third label should have the caption Of. The fourth label should be blank, but name it lblTracks (plural). Leave the default names for the first and third labels. Place a label with a blank caption centered below the MDI control, too. Name it lblStatus. You also might want to kick the point size of the font for all those labels up to 12 points. When you're done, your form should look like Figure 9.2.


  4. Figure 9.2. The CD Player form.

  5. Set the caption of the form to CD Player. Presumptuous of us, considering it doesn't do anything, yet. But have faith—it soon will.

  6. To get the application off to a good start, go to the Form Load event and type Listing 9.1.

  7. Private Sub Form_Load()
    
    MMControl1.DeviceType = "CDAudio"
    
    MMControl1.Command = "Open"
    
    End Sub
  8. Just tell the application what device you want it to access and tell it to open. This control has the peculiarity of enabling you to tell it what to do by assigning strings to its Command property. There is, in fact, a whole sublanguage here that you can use. You'll explore it later in this chapter.

    Listing 9.2 shows the corresponding Form Unload event. Nice and tidy. And that's it for the form.

  9. Private Sub Form_Unload(Cancel As Integer)
    
    MMControl1.Command = "Close"
    
    End Sub
  10. Double-click the control and choose the StatusUpdate event. This is an event that is tied to a built-in timer. You can set the timer's interval by using the control's UpdateInterval property. Set the UpdateInterval to 500. This number is in milliseconds (just like the timer interval), and 500 makes the StatusUpdate event fire off twice a second.

    So what do you use your application for? Well, often you'll want to update controls on-screen with information coming from the multimedia driver. You might show what frame the AVI video is displaying or how many tracks are on the audio CD. Speaking of which, check out Listing 9.3.

    The big If-Then-ElseIf figures out what mode the device is currently in and sets lblStatus appropriately. As you can see, this is where you put those constants in the WINMMSYS.TXT file to use.

  11. Private Sub MMControl1_StatusUpdate()
    
    If MMControl1.Mode = MCI_MODE_NOT_READY Then
    
        lblStatus.Caption = "Not Ready"
    
    ElseIf MMControl1.Mode = MCI_MODE_STOP Then
    
        lblStatus.Caption = "Stop"
    
    ElseIf MMControl1.Mode = MCI_MODE_PLAY Then
    
        lblStatus.Caption = "Play"
    
    ElseIf MMControl1.Mode = MCI_MODE_RECORD Then
    
        lblStatus.Caption = "Record"
    
    ElseIf MMControl1.Mode = MCI_MODE_SEEK Then
    
        lblStatus.Caption = "Seek"
    
    ElseIf MMControl1.Mode = MCI_MODE_PAUSE Then
    
        lblStatus.Caption = "Pause"
    
    ElseIf MMControl1.Mode = MCI_MODE_OPEN Then
    
        lblStatus.Caption = "Open"
    
    End If
    
    lblTrack.Caption = Str(MMControl1.Track)
    
    lblTracks.Caption = Str(MMControl1.Tracks)
    
    End Sub
  12. Now just fill in the current track number and the number of total tracks.

Believe it or not, you're done. Just pop in an audio CD. If the Windows automatic CD player comes up, close it right away. Then run your application. If everything goes as planned, you should see a window that looks something like Figure 9.3.


Figure 9.3. Your CD player in action.

What are you waiting for? Click Play! Try out the Skip to Next Song button (the arrow pointing to a line on the right). And the Previous Song button. Stop, Pause, and Eject should work, too. Pretty impressive for a few lines of code, aye?

Notice how the buttons change, depending on which are disabled and which are available. This is a handy feature, and it is automatic. Well, almost automatic. You have to make sure that the MCI control's AutoEnable property is True. But because that's the default, you're set.

Your MCI can control two classes of devices. The audio CD, along with the VCR and video disc player, are called simple devices. WAVs and AVIs are referred to as compound devices, because they require you to specify a file name in order for them to work. The next section shows you how tough it would be to turn your simple device player into a compound one.

Project 2 A WAV Player

The next task is to create a WAV player. You should begin with your CD player as a base. You might want to save the project and files to a different name if you want to keep your CD player intact. When you are ready, follow these steps:

  1. Delete all four Track labels above the MCI control. Drop an edit control and a button on the form. Name the edit control txtFileName and name the button cmdOpen. Set the Default property of the Open button to True. And don't forget to change the caption of the form to Wave Player. Your form now should look like Figure 9.4.

  2. Take a look at the Form Load event. Change it so that it looks like Listing 9.4.


  3. Figure 9.4. Moving things around to create a Wave player application.

    Private Sub Form_Load()
    
    MMControl1.DeviceType = "WaveAudio"
    
    End Sub
  4. You can't open the device here like you did with the CD player because you don't have all the information you need. You still must have the file name of the WAV file. All you can do is tell it that you'll be playing WAVs.

    Listing 9.5 shows the Click event for the Open button.

  5. Private Sub cmdOpen_Click()
    
    MMControl1.filename = txtFileName.TEXT
    
    MMControl1.Command = "Open"
    
    End Sub
  6. After the file name is known and entered into txtFileName, you can open the device and play it.

  7. Finish up by going to the StatusUpdate event of the MCI control and deleting the lines that filled in the track information. The final event should look like Listing 9.6.

  8. Private Sub MMControl1_StatusUpdate()
    
    If MMControl1.Mode = MCI_MODE_NOT_READY Then
    
        lblStatus.Caption = "Not Ready"
    
    ElseIf MMControl1.Mode = MCI_MODE_STOP Then
    
        lblStatus.Caption = "Stop"
    
    ElseIf MMControl1.Mode = MCI_MODE_PLAY Then
    
        lblStatus.Caption = "Play"
    
    ElseIf MMControl1.Mode = MCI_MODE_RECORD Then
    
        lblStatus.Caption = "Record"
    
    ElseIf MMControl1.Mode = MCI_MODE_SEEK Then
    
        lblStatus.Caption = "Seek"
    
    ElseIf MMControl1.Mode = MCI_MODE_PAUSE Then
    
        lblStatus.Caption = "Pause"
    
    ElseIf MMControl1.Mode = MCI_MODE_OPEN Then
    
        lblStatus.Caption = "Open"
    
    End If
    
    End Sub
  9. The only other event was the Close of the form, which sent a Close command to the MCI. This is fine as it is, so run it (see Figure 9.5).

  10. Notice that all the buttons are disabled when the application first comes up. This is because the Open command hasn't been executed yet. Type a path and file name of a WAV file on your hard drive. For example, type the following:

    c:\windows\media\chimes.wav

  11. Press Enter or click the Open button. The MCI comes to life and you can play your WAV. You'll have to rewind it to play it a second time.


Figure 9.5. The Wave Player application.

Notice one other thing. There is another button that is enabled that wasn't enabled for the audio CD player. The big round circle. Yes, this is the Record button. You also can use your new little utility to record WAV files. Actually, you have no way of creating new wave files (that would take some more work), but you can record at the beginning or end of the sound file in memory and then play it back. But again, you don't have any way of saving the recording back out as it is right now. You'll see how you would go about saving recordings as new WAV files later in this chapter.

Project 3 Video

On to bigger and better players. The MCI control can do more than make your sound card chirp. It actually can play back video for your viewing pleasure. The first question you no doubt will be asking is, "Where, exactly, does it play this video?" Do you punch a button and it grows a screen to project it on?

Not exactly. The fact is that you need to drop another control on the form. A picture control. Then you connect the picture control to the MCI and it plays the video there.

To play back your video, follow these steps:

  1. Stretch out your form window and add the picture control below the file name edit control. The form should look like Figure 9.6.

  2. Name the picture control picVid. Don't forget to change the form caption to AVI Player.

  3. Believe it or not, the only code change you need to make is in the Form Load event (see Listing 9.7).


Figure 9.6. The AVI video player form.

Private Sub Form_Load()

MMControl1.DeviceType = "AVIVideo"

MMControl1.hWndDisplay = picVid.hWnd

End Sub
  1. Change DeviceType to AVIVideo. Then add a line to make the connection between the MCI control and the picture control. The hWnd property is the Windows handle for the picture control. Anytime you want to refer to a window or control when interfacing with a DLL or Win32, you should use this attribute. You use it here to fill in the hWndDisplay attribute of the MCI control, which always needs to be assigned the window handle of the object you want to use for the video output. This makes the connection.

    Run your new video player (see Figure 9.7).

  2. Again, the buttons are disabled until you type a file name and click Open. Try this one:

    c:\windows\help\whatson.avi

    Or this one:

    :\windows\help\explorer.avi


Figure 9.7. Running the AVI video player.

Or, type any file name that you happen to have on your hard drive or CD-ROM. It's just that easy.

Delving Deeper into the MCI Control

So far, you have learned about the fundamental functionality available with the MCI control. You can take advantage of many more attributes and events, however, to enhance your multimedia application. In this section, you will learn about the most important enhancements you can make.

Enabled, Visible, and AutoEnable

Earlier in this chapter, you learned that when AutoEnable is set to True, it turns over the handling of the appropriate enabling and disabling of the individual buttons on the MCI control to the system. Normally, you want AutoEnable to be True. If you set AutoEnable to False, you can use the ButtonEnable properties to set the buttons yourself. (No ButtonEnable property actually exists. ButtonEnable is just an easy way to refer collectively to these nine properties: BackEnable, EjectEnable, NextEnable, PauseEnable, PlayEnable, PrevEnable, RecordEnable, StepEnable, and StopEnable.) Keep in mind that if the AutoEnable property is set to True, it overrides any ButtonEnable property settings you have explicitly set yourself. In other words, if you want to use the ButtonEnable properties, you'll have to set AutoEnable to False.

Regardless of whether you handle the enabling and disabling of the buttons or you let AutoEnable handle it for you, there will be times when you want a button to be completely invisible. The ButtonVisible properties enable you to make a button invisible. Again, ButtonVisible is shorthand for the collection of visible properties associated with each button.

A Visible property and Enabled property also exist for the entire control. These properties supersede all the Button properties and the AutoEnable property.

DeviceType and FileName

You've seen these properties already. You used DeviceType to specify what type of device you would be opening for each of the different players. For the audio CD player, you used CDAudio; for the Wave player, you used WaveAudio. And for the AVI player, you used AVIVideo. The other possible values for the DeviceType property are DAT, DigitalVideo, MMMovie, Other, Overlay, Scanner, Sequencer, VCR, and Videodisc.

FileName, of course, is used with compound devices to indicate which file they should use.


TIP

You don't have to specify the DeviceType when you are using a compound device and the extension on the file name makes it clear which device should be used.

For instance,

MMControl1.filename = "MyWav.WAV"
MMControl1.Command = "Open"

This code would cause Visual Basic to open a WaveAudio device even though you never set the DeviceType attribute because it surmised the information from the filename extension (WAV).

UpdateInterval, StatusUpdate, and Mode

As you saw from the MCI control projects earlier, at every UpdateInterval (specified in milliseconds), the StatusUpdate event is triggered. This event generally is used to update status displays on-screen, such as the mode in which you are working.

Mode gives you the current mode the MCI device is in, such as Stop, Play, Record, Pause, and so on. Mode is read-only and is available only at runtime.

Other attributes often displayed in the StatusUpdate event are Track, Tracks, Length, Position, TrackLength, and TrackPosition.

Track and Tracks

You've seen these properties before in this chapter. These determine the current track and the number of the final track. Track can be set to change the current track. Tracks is read-only. Both properties are available only at runtime.

UsesWindows and hWndDisplay

The UsesWindows property tells you whether the current device uses a window (or picture control) to present its output. This property is True for MMMovie, Overlay, VCR, or AVIVideo.

The hWndDisplay property, as you saw in the AVI player example, specifies which control displays the output. You always assign another control's hWnd property to this property.

Orientation

The Orientation property tells Visual Basic to lay out the buttons horizontally (0, the default) or vertically (1).

Silent

This property works like a Mute button. Set it to True, and all sound stops.

The Can-Can

The MCI control has several properties that give you information about the capabilities of the device with which you are working. These properties are CanEject, CanPlay, CanRecord, and CanStep. They are each simple True/False variables and can be read only at runtime.

In addition, you can use the DeviceID property to determine the ID of the currently open device at runtime.

RecordMode

When you record to a medium, you can use the RecordMode property to specify that it insert the recorded material in the middle of what's there (0) or simply overwrite it (1). You can tell whether a medium is recordable by enabling CanRecord, but no attribute exists to let you know whether the medium supports Insert, Overwrite, or both modes. You just have to try it; if one mode fails, try the other mode. Nifty. I can tell you that WAVs can support only Insert mode, and one would assume that VCRs would support only Overwrite mode. From there, you're on your own.

TimeFormat

Many properties are set using values based on the current TimeFormat. The TimeFormat property enables you to specify how you want to reference points in your media. Certain time formats make sense with certain media. If you assign a format with a media that doesn't make sense, the assignment is ignored. Table 9.1 lists the acceptable values for TimeFormat.

Constant


Value


Meaning


mci_Format_Milliseconds

0

Milliseconds

mci_Format_Hms

1

Hours, minutes, seconds

mci_Format_Msf

2

Minutes, seconds, frames

mci_Format_Frames

3

Frames

mci_Format_Smpte_24

4

24-frame SMPTE: Hours, minutes, seconds, frames

mci_Format_Smpte_25

5

25-frame SMPTE: Hours, minutes, seconds, frames

mci_Format_Smpte_30

6

30-frame SMPTE: Hours, minutes, seconds, frames

mci_Format_Smpte_30Drop

7

30-drop-frame SMPTE: Hours, minutes, seconds, frames

mci_Format_Bytes

8

Number of bytes

mci_Format_Samples

9

Number of samples

mci_Format_Tmsf

10

Tracks, minutes, seconds, frames

Each of these formats stores its data in a four-byte integer. It is up to you to decode it. For example, mci_Format_Hms stores the hours, minutes, and seconds from the least-significant byte to the most-significant byte in a four-byte Long value.

If you were checking the position at 1 hour, 5 minutes, and 3 seconds, for example, it would be stored like the following:

[murphy]


Most-Significant Byte 4


Byte 3


Byte 2


Least-Significant Byte 1


Decimal

0

3

5

1

Binary

00000000

00000011

00000101

00000001


Note

The last (most significant) byte is not needed.

If this looks backward to you, remember that numbers generally are read from right to left. The least-significant digit (the 1s, in decimal) always is the farthest to the right, and the digits become larger and larger (tens, hundreds, and so on) as you move to the left. This process also is used with binary numbers.

The problem is, when you check the value of the Long number, it is 197889. That's because the bytes are taken together to mean one really Long binary value. The decimal values for each of the On bits add up like this:

1 + 256 + 1024 + 65536 + 131072 = 197889

(I just love binary math.)

But the value 197889 is useless to us. How do we pry 1 hour, 5 minutes, and 3 seconds out of it? This sort of storage scheme is common for Win32 functions, and you see it more and more now in Visual Basic's native functions, too. The problem is, there is no built-in function for extracting individual byte values out of a four-byte Long value. Because this need is becoming so common, I will spend a little time here showing you how to do it. It isn't difficult, but it isn't immediately obvious, either.

All it takes is a little bit masking and some division. Bit masking is a way of pulling just the data you want out of a Long binary number, which happens to be just what we want to do.

To see the lowest order byte of the number in this example (the hours), you can take the following approach:

Binary:

00000000

00000011

00000101

00000001

AND

00000000

00000000

00000000

01111111

_______________________________________________________________

[murphy]

00000000

00000000

00000000

00000001

An AND logical operator only allows a bit in the result if both the corresponding bits in the problem are 1. By doing an AND with a number that only has 1s in the least-significant byte, you get only the value from that byte. By the way, you only want to check the first seven bits. The eighth bit is the sign, and you won't be getting signed values back under normal circumstances.

And the answer is 1. One hour. One down, two to go.

Can you use the same trick for the minutes?

Binary:

00000000

00000011

00000101

00000001

AND

00000000

00000000

01111111

00000000

_______________________________________________________________

[murphy]

00000000

00000000

00000101

00000000

Well, you masked out all the other bytes, but the value is still 1280 (256 + 1024). You need to shift the byte over to the least-significant value position. How do you do it? Well, if you wanted to shift the 7 in 700 to the lowest position, what would you do? Divide by 100. That would give you 7.

So you just need to divide by 100000000 (binary) or 256. 1280 divided by 256 equals 5. That's it! Five minutes. One more.

Binary:

00000000

00000011

00000101

00000001

AND

00000000

01111111

00000000

00000000

______________________________________________________________

[murphy]

00000000

00000011

00000000

00000000


Got the byte. 196608 is the number. Now divide by binary 10000000000000000 (16 zeros—count 'em). That's 65536 in decimal. 196608 divided by 65536 equals 3. One hour, five minutes, and three seconds. Cool.

But that seems like a lot of work just to get the position. Why couldn't they make it easier? They could have. But there is always the trade-off between efficiency and programming simplicity. This time, the programmers opted for efficiency. You can easily turn this into a function. Add Listing 9.8 to your library.

Public Function ByteFromLong(LongVal As Long, Position As Integer) As Integer

Dim iTemp As Long

If Position < 1 Or Position > 4 Then

   ByteFromLong = —1

   Exit Function

End If

Select Case Position

Case 1

   ' 127 = Binary 01111111

   iTemp = LongVal And 127

Case 2

   ' 32512 = Binary 01111111 00000000

   iTemp = LongVal And 32512

   ' 256 = Binary 1 00000000

   iTemp = iTemp / 256

Case 3

   ' 8323072 = Binary 01111111 00000000 00000000

   iTemp = LongVal And 8323072

   ' 65536 = Binary 1 00000000 00000000

   iTemp = iTemp / 65536

Case 4

   ' 2130706432 = Binary 01111111 00000000 00000000 00000000

   iTemp = LongVal And 2130706432

   ' 16777216 = Binary 1 00000000 00000000 00000000

   iTemp = iTemp / 16777216

End Select

ByteFromLong = iTemp

End Function

On the CD that comes with this book, you will find this function as part of an application called LongDissector. The form looks like Figure 9.8.


Figure 9.8. The form for LongDissector.

The button's Click event uses the ByteFromLong function, as you can see in Listing 9.9.

Private Sub cmdFigureIt_Click()

Dim iLong As Long

iLong = Val(txtLong.TEXT)

lblByte1.Caption = Str(ByteFromLong(iLong, 1))

lblByte2.Caption = Str(ByteFromLong(iLong, 2))

lblByte3.Caption = Str(ByteFromLong(iLong, 3))

lblByte4.Caption = Str(ByteFromLong(iLong, 4))

End Sub

Now you easily can extract information out of a Long value for all the functions that return a value based on the TimeFormat (just as you can for any other functions in Visual Basic or Win32 that use this type of return value).

From and To

These properties can be set with values to indicate a portion of media that should be played. From and To enable you to play a snippet from the middle of a WAV or a single scene from an AVI video. You also can use From and To with the Record command.

The From and To property definitions apply only to the next command given.

These properties are specified in the format set by TimeFormat. To assign a value to these properties, you might need to pack your own Long value with specific bytes of information. You must modify the function shown in Listing 9.9 to allow it to assign a value to a given byte, rather than to retrieve it. I'll leave this one up to you to try.

Length, Position, TrackLength, TrackPosition, and Start

As their names imply, these properties give you the length and position of the currently open media or the currently specified track. Start gives you the starting position of the current media.

These properties are all read-only and available only at runtime.

Notify, NotifyValue, NotifyMessage, and the Done event

Notify is a Boolean that can be set to True to cause the next command to perform a callback when it is done—that is, the Done event is triggered when the next command completes its task. The Notify assignment applies only to the next command issued. If Notify is not specified before a command, that command uses its default notification. The default notification is different for each command (see "Commands and Errors," later in this chapter).

NotifyValue and NotifyMessage can be accessed in the Done event to find out exactly how the last command went. You can determine whether it was successful, whether it was aborted by the user, or whether it failed for some reason. Table 9.2 lists the constants associated with NotifyValue.

Constant


Value


Meaning


mci_Notify_Successful

1

Completed successfully

mci_Notify_Superseded

2

Another command overrode this one.

mci_Notify_Aborted

4

Aborted by the user

mci_Notify_Failure

8

Failed

NotifyMessage is simply a textual description of NotifyValue. It is handy for dropping into a message box or a status bar.

Wait

Wait determines whether the next command waits until it finishes its processing before returning control to the application. The default depends on the command executed (see "Commands and Errors," later in this chapter, for a list of the commands).

Shareable

This Boolean enables you to specify whether other applications can share the currently open device.

Commands and Errors

The Command property is not used to set a value or to specify the way things should be carried out, as most properties are used. Command is a special way to tell the MCI control to do something. You already saw the most commonly used commands in the examples earlier in this chapter. In this section, I will talk briefly about each command, how it works, and what it impacts.

Open and Close

These commands open and close the device specified in DeviceName. If it is a compound device, FileName is used to locate the associated file.

Play and Record

These commands play from or record to the media. Play and Record look at the From and To properties and use the values specified there to locate the media and to determine how much of the media to work on. Record also uses RecordMode to determine whether it should insert or overwrite the new information.

Pause and Stop

Pause pauses the playback or recording. If this command is executed while in Pause mode, it acts as a toggle and attempts to resume whatever it was doing before.

Stop stops playing or recording.

Back, Step, Prev, and Next

Back and Step act like a Rewind and Fast Forward button on the current track. You can use the Frames property to fine-tune how far back and forward these commands take you.

Prev and Next move to the start of the current track and to the next track.

Seek

Seek moves the current location (whether the MCI control is currently playing or not) to the place specified in the To property. If it is playing, it continues playing at the new position.

Eject

This command ejects the media.

Sound

This command plays a sound specified in FileName.

Save

This command saves a currently open file on a compound device to the file name specified in FileName. This is what you would have needed to make the recording session with your Wave player worthwhile.

Notify and Wait

The Notify and Wait properties affect the next command given. You only need to use them, though, when you want the next command to work differently than it normally works. Table 9.3 lists the default behavior for each command.

Command


Default Notify


Default Wait


Back

False

True

Close

False

True

Eject

False

True

Next

False

True

Open

False

True

Pause

False

True

Play

True

False

Prev

False

True

Record

True

False

Save

False

True

Seek

False

True

Sound

False

False

Step

False

True

Stop

False

True

Error and ErrorMessage hold the error number and error description (respectively) for the last MCI command. If there was no error, Error is zero.

Beyond the MCI Control

Consensus has it that the MCI control doesn't win any awards for beauty. But it is highly functional. And it makes something that could be very difficult very easy. To work around this appearance problem, some developers simply use the MCI control with its Visible property set to False. Any commands they want to offer to the user are provided through the developer's user interface, which is, presumably, much more attractive. Then the properties of the control are manipulated in code behind the scenes. This is a perfectly workable solution and gives you a lot of flexibility without tying you to visual controls.

If you want to go to the next level, though, you can access the MCI through Win32's multimedia API. Specifically, you can use the mciSendString function. Listing 9.10 shows the declaration.

Declare Function mciSendString Lib "winmm" _

(ByVal lpstrCommand As String, _

ByVal lpstrReturnString As String, _

ByVal uReturnLength As Integer, _

ByVal hWndCallback As Integer) As Long

NOTE

Keep in mind that if you include \WinAPI\WINMMSYS.TXT as a module in your application, not only are all the multimedia constants already defined, but all the multimedia Win32 functions also are declared for you. Don't declare the functions a second time in your application.

The lpstrCommand argument is where you send the actual command (like Play, Stop, or Record). lpstrReturnString is where you receive information back from the multimedia system (like status information requested), and uReturnLength is where you pass the length of the string. (Actually, you want to pass the length minus 1 so that there is room for the string ending character.)

Finally, hWndCallback is the hWnd pointer to a window that will receive the callback function. This is analogous to the Notify property and the Done event of the control. Unless you trap for the mm_Mcinotify for a particular window (using a third-party tool to trap events Visual Basic doesn't normally trap) and then pass that window's hWnd property here, however, you won't be able to take advantage of it.

mciSendString returns a value if there was an error, or 0 if everything went fine. There are a large number of possible error codes that can be returned. For a complete list, open WINMMSYS.TXT (in your WinAPI directory) and search for MCIERR_INVALID_DEVICE_ID. This is the first error code. A long list follows this first error code.

After you declare the function, you are ready to put it to use. Listing 9.11 provides an example bit of code that opens the audio CD player and begins playing. It also shows you some status updates with the message box.

Dim ReturnString As String

Dim rc As Integer

'Always set your string size before sending to a DLL

ReturnString = String(128, " ")

' Opens the audio CD device.

rc = mciSendString("open CDAudio", ReturnString, 127, 0)

' Plays an audio CD.

rc = mciSendString("play CDAudio", ReturnString, 127, 0)

' Request the mode be returned

rc = mciSendString("status CDAudio mode", _

   ReturnString, 127, 0)

MsgBox (ReturnString)

' Returns the number of tracks on the current audio CD

rc = mciSendString("status CDAudio number of tracks", _

   ReturnString, 127, 0)

MsgBox (ReturnString)

' Closes the audio CD device.

rc = mciSendString("close CDAudio", ReturnString, 127, 0)

The commands you can specify in the lpstrCommand string can be quite extensive. The commands and options available depend on the device. Because there's no way I can provide an exhaustive list here of all the things you can do, I will show you some examples of common strings you might want to try in Listing 9.12. This isn't intended to be a sequential listing, but rather a list of separate examples of strings that you could use to control all different kinds of devices.

play c:\windows\media\chimes.wav

open new type WaveAudio alias wave

set wave bitpersample 8

set wave samplespersec 11025

set wave channels 2

record wave

stop wave

save wave c:\mywave\mywave.wav

close wave

capability WaveAudio can save

capability CDAudio can reverse

capability AVIVideo has audio

open c:\vid.avi

play WaveAudio

play VCR fast

play VCR reverse

play VCR slow

resume CDAudio

seek CDAudio to start

set CDAudio left off

set AVIVideo time format SMPTE 24

status WaveAudio bitspersample

status CDAudio length

status CDAudio length track 5

status VCR media present

stop VCR

If you want a more complete list of available MCI commands, see Microsoft's Multimedia Programmer's Reference.

Keep in mind that more and more consumer audio and video equipment now supports MCI. So the next time you go out to buy a video disc player or a do-everything VCR or DAT tape deck, you might want to check whether it supports MCI. If you buy equipment that does support MCI, you usually can install it on a serial port.

Summary

In this chapter, you began by creating several complete multimedia players that easily went together, thanks to Visual Basic's MCI control. Then you dove deeper into the control to learn about all its rich features and capabilities. Finally, you finished by going one level deeper—using the mciSendString Win32 function. This function enabled you to send English-like strings directly to the MCI to control all the devices the MCI control accessed.

Previous Page TOC Next Page